﻿using Microsoft.SharePoint;
using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using SP = Microsoft.SharePoint.Client;

namespace ListCopyCOM
{
  public  static class ListCopyComLibrary
    {
         public static void CopySharePointList(string sourceSiteUrl, string targetSiteUrl, string sourceListName, string targetListName)
        {
            ClientContext sourceClientContext = new ClientContext(sourceSiteUrl);
            ClientContext targetClientContext = new ClientContext(targetSiteUrl);

           List listname= GetListByTitle(targetClientContext, targetListName);
           if (listname == null)
           {
                CreateList(targetClientContext, targetListName);
            }
            System.Collections.Generic.List<string> targetFields = ListFields(targetClientContext, targetListName);
            System.Collections.Generic.List<string> sourceFields = ListFields(sourceClientContext, sourceListName);
            /*
             * Same site so easy copy
             */ 
            if (sourceSiteUrl.Equals(targetSiteUrl))
            {
                List targetList = sourceClientContext.Web.Lists.GetByTitle(targetListName);
                targetClientContext.Load(targetList.Fields);
                targetClientContext.ExecuteQuery();

                foreach (var item in sourceFields)
                {
                    if (!targetFields.Contains(item))
                    {
                        Console.WriteLine(" field to add " + item);

                        string xmlstring = GetFieldDescrAsXML(sourceClientContext, sourceListName, item);
                        XDocument fieldXdoc = XDocument.Parse(xmlstring);
                        fieldXdoc.Descendants().Where(e => e.Name == "ID").Remove();
                        fieldXdoc.Descendants().Where(e => e.Name == "SourceID").Remove();
                        AddFieldOptions asdsa = new AddFieldOptions();
                        Field f = targetList.Fields.AddFieldAsXml(fieldXdoc.ToString(), false, asdsa);
                        f.Update();
                        sourceClientContext.ExecuteQuery();

                    }
                }
            }
            else
            {
                List targetList = sourceClientContext.Web.Lists.GetByTitle(targetListName);
                targetClientContext.Load(targetList.Fields);
                targetClientContext.ExecuteQuery();

                foreach (var item in sourceFields)
                {
                    if (!targetFields.Contains(item))
                    {
                        Console.WriteLine(" field to add " + item);

                        string xmlstring = GetFieldDescrAsXML(sourceClientContext, sourceListName, item);
                        /*
                         * try and remove the unused fields
                        */
                        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                        XDocument fieldXdoc = XDocument.Parse(xmlstring);
                        fieldXdoc.Descendants().Where(e => e.Name == "ID").Remove();
                        fieldXdoc.Descendants().Where(e => e.Name == "SourceID").Remove();
                        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                       if(item.GetType().Equals("LookUp") ){
                           XElement  XListID=fieldXdoc.Descendants().Where( e=> e.Name == "List").First();
                           Guid listGuid= new Guid(XListID.Value);
                           List list = sourceClientContext.Web.Lists.GetById(listGuid);
                           string lookupSourceList = list.Title;
                           CopySharePointList(sourceSiteUrl, targetSiteUrl, lookupSourceList, targetListName);
                        }

                        AddFieldOptions asdsa = new AddFieldOptions();
                        Field f = targetList.Fields.AddFieldAsXml(fieldXdoc.ToString(), false, asdsa);
                        f.Update();
                        sourceClientContext.ExecuteQuery();

                    }
                }
            }
           
        }

        private static void CreateList(ClientContext clientContext, string listName)
        {
            Web oWebsite = clientContext.Web;
            ListCreationInformation listCreationInfo = new ListCreationInformation();
            listCreationInfo.Title = listName;
            listCreationInfo.TemplateType = (int)ListTemplateType.GenericList;

            List oList = oWebsite.Lists.Add(listCreationInfo);

            clientContext.ExecuteQuery();
        }

        private static System.Collections.Generic.List<string> ListFields(ClientContext context,string listName)
        {
            List <string> fieldList = new List <string>();
            List list = context.Web.Lists.GetByTitle(listName);
            context.Load(list.Fields);

            // We must call ExecuteQuery before enumerate list.Fields. 
            context.ExecuteQuery();
            
            foreach (Field field in list.Fields  )
            {
                //System.Console.WriteLine(field.InternalName + "  " + field.Title + "   "+ "   "+ field.SchemaXml  +  "    " + field.GetType()   );
                System.Console.WriteLine(field.SchemaXml);
                fieldList.Add(field.InternalName);
               
            }

            return fieldList;
        }


        private static System.Collections.Generic.List<string> CheckListForLookupFields(ClientContext context, string listName)
        {
            List<string> fieldList = new List<string>();
            List list = context.Web.Lists.GetByTitle(listName);
            context.Load(list.Fields);
            context.ExecuteQuery();

            foreach (Field field in list.Fields)
            {
                if (!SPBuiltInFieldId.Contains(field.Id))
                {
                    System.Console.WriteLine(field.GetType().FullName + "        " + field.InternalName + "        " + SPBuiltInFieldId.Contains(field.Id));
                }
               if(field.GetType().Equals("LookUp") ){
                   fieldList.Add(field.InternalName);
               }
            }
            return fieldList;
        }

        public static List GetListByTitle(ClientContext clientContext, String listTitle)
        {
            List existingList;

            Web web = clientContext.Web;
            ListCollection lists = web.Lists;

            IEnumerable<List> existingLists = clientContext.LoadQuery(
                    lists.Where(
                    list => list.Title == listTitle)
                    );
            clientContext.ExecuteQuery();

            existingList = existingLists.FirstOrDefault();

            return existingList;
        }
        private static string GetFieldDescrAsXML(ClientContext context, string listName,string field)
        {
            List list = context.Web.Lists.GetByTitle(listName);
            context.Load(list.Fields);
            context.ExecuteQuery();
            foreach (Field column in list.Fields)
            {
                if (column.InternalName.Equals(field))
                {
                    return column.SchemaXml;
                }
            }
            return "";
        }

      public static System.Collections.Generic.List<string> GetSiteLists( string url){
          ClientContext clientContext = new ClientContext(url);
          Web oWebsite = clientContext.Web;
          ListCollection collList = oWebsite.Lists;

          clientContext.Load(collList);
          try
          {
              clientContext.ExecuteQuery();
          }
          catch (Exception e)
          {
              System.Console.WriteLine(e.Message);
            
          }
        


          System.Collections.Generic.List<string> listOfLists = new System.Collections.Generic.List<string>();
          foreach (SP.List oList in collList)
          {
              listOfLists.Add( oList.Title.ToString()   );
          }

          return listOfLists;
      }


        

        
    }
    }

